using System.Collections.Generic;
using UnityEngine;
using XNode;

namespace JufGame
{
	[CreateAssetMenu(menuName = ("LOD Trader/FeatureGraph"), fileName = ("FeatureGraph"))]
	public class FeatureGraph : NodeGraph
	{
		public List<FeatureSolution> CompleteSolutions => completeSolutions;
		public int DefaultSolutionID => defaultSolutionID;
		private static Vector4 limitResourceMul = Vector4.one * 0.1f;//拟定资源因子下限，用以估算W矩阵，可根据实际修改
		[SerializeField] private List<FeatureSolution> completeSolutions;
		[SerializeField, Tooltip("初始特征解决方案在CompleteSolutions的下标")] private int defaultSolutionID;
		
		//游戏开始时，计算所有特征解决方案的预处理的数据
		private void OnEnable()
		{
			var upgradeWs = new List<Vector3>();
			var downgradeWs = new List<Vector3>();
			for(int i = 0; i < completeSolutions.Count; ++i)
			{
				CalcTranstions(completeSolutions[i], upgradeWs, downgradeWs);
				completeSolutions[i].InitSolution();
				completeSolutions[i].InitWMatrixs(upgradeWs, downgradeWs);
				upgradeWs.Clear();
				downgradeWs.Clear();
			}
		}
		/// <summary>
		/// 计算解决方案的可转换列表
		/// </summary>
		/// <param name="startSolution">需计算的方案</param>
		private void CalcTranstions(FeatureSolution startSolution, List<Vector3> upgradeWs, List<Vector3> downgradeWs)
		{
			for(int i = 0; i < completeSolutions.Count; ++i)
			{
				if (FeatureSolution.IsSameID(startSolution, completeSolutions[i]))
				{
					continue;
				}	
				startSolution.InitTranstions(completeSolutions[i], limitResourceMul, upgradeWs, downgradeWs);
			}
		}

		#region 仅在Unity编辑时使用
		#if UNITY_EDITOR
		[SerializeField, Tooltip("特征图根节点在Nodes列表中的下标")] private int RootNodeIndex;
		/// <summary>
		/// 初始化特征图，并计算其初始数据
		/// </summary>
		public void UI_InitGraph()
		{
			completeSolutions = new List<FeatureSolution>();
			var rootFeature = (LOD_Feature)nodes[RootNodeIndex];
			if(rootFeature == null)
			{
				Debug.LogWarning("未设置根细节特征");
				return;
			}
			for(int i = 0; i < nodes.Count; ++i)
			{
				if(nodes[i] is LOD_Feature featureNode)
				{
					featureNode.InitConfigs();
				}
			}
			FindFeatureSolutions(rootFeature);
			//寻找最大鲁莽度的特征解决方案作为初始方案
			var cheapestEva = float.MaxValue;
			for(int i = 0; i < completeSolutions.Count; ++i)
			{
				completeSolutions[i].CalcTotalDatas();
				completeSolutions[i].OnlyID = i;
				var evaluation = completeSolutions[i].TotalCost.sqrMagnitude;
				if(evaluation < cheapestEva)
				{
					cheapestEva = evaluation;
					defaultSolutionID = completeSolutions[i].OnlyID;
				}
				completeSolutions[i].FinishInit();
			}
			Debug.Log("保存成功");
		}

		/// <summary>
		/// 查找所有的特征方案
		/// </summary>
		/// <param name="rootFeature">初始特征</param>
		private void FindFeatureSolutions(LOD_Feature rootFeature)
		{
			completeSolutions.Clear();
			var incompleteSolutions = new Queue<FeatureSolution>();
			// 初始化不完整解决方案队列，包含一个空解决方案
			incompleteSolutions.Enqueue(new FeatureSolution());
			while (incompleteSolutions.Count > 0)
			{
				// 从不完整解决方案队列中取出一个解决方案
				var solution = incompleteSolutions.Dequeue();
				var requiredFeatures = new HashSet<LOD_Feature>{ rootFeature };
				requiredFeatures.UnionWith(GetRequiredFeatures(solution));
				var chosenFeatures = solution.GetAllFeatures();
				// 如果所需特征与已选择特征相匹配，则将该解决方案添加到完整解决方案列表中
				if (requiredFeatures.SetEquals(chosenFeatures))
				{
					completeSolutions.Add(solution);
				}
				else
				{
					// 从所需特征集合中选择一个特征
					LOD_Feature feature = null;
					foreach(var f in requiredFeatures)
					{
						if(!chosenFeatures.Contains(f))
						{
							feature = f;
							break;
						}
					}
					// 遍历该特征的LOD，尝试所有可能的选择
					for (int i = 0; i < feature.Configs.Length; ++i)
					{
						// 复制当前解决方案以创建一个新的解决方案
						var newSolution = solution.Clone();
						// 添加特征和LOD的选择到新解决方案
						newSolution.AddChoice(feature, i);
						if (!IsViolateConstraint(newSolution, feature, i))
						{	
							//将新解决方案添加到不完整解决方案队列中(这一步需确保没有违反约束)
							incompleteSolutions.Enqueue(newSolution);
						}
					}
				}
			}
		}
		/// <summary>
		/// 检查新特征的LOD在该方案下是否违反约束
		/// </summary>
		/// <param name="solution">特征方案</param>
		/// <param name="f">新特征</param>
		/// <param name="configIndex">该特征的LOD</param>
		/// <returns>确定违反约束</returns>
		private bool IsViolateConstraint(FeatureSolution solution, LOD_Feature f, int configIndex)
		{
			var constraints = f.GetConstraintsByCfgIdx(configIndex);
			if(constraints != null)
			{
				foreach(var c in constraints)
				{
					if(c.Value != solution.GetLODForFeature(c.Key))
					{
						return true;
					}			
				}			
			}
			return false;
		}
		private HashSet<LOD_Feature> GetRequiredFeatures(FeatureSolution solution)
		{
			var requiredFeatures = new HashSet<LOD_Feature>();
			foreach (var feature in solution.FeatureConfigs)
			{
				var children = feature.Key.GetChildFeaturesByCfgIdx(feature.Value);
				if (children.Count > 0)
				{
					requiredFeatures.UnionWith(children);
				}
			}
			return requiredFeatures;
		}		
		#endif
		#endregion
	}
}
